Skip to content

Fail loudly when the OIDC workflow-file check silently skips a run - #55

Merged
Mearman merged 1 commit into
mainfrom
feat/loud-workflow-validation-skip
Sep 10, 2026
Merged

Fail loudly when the OIDC workflow-file check silently skips a run#55
Mearman merged 1 commit into
mainfrom
feat/loud-workflow-validation-skip

Conversation

@Mearman

@Mearman Mearman commented Sep 10, 2026

Copy link
Copy Markdown
Member

Traced a real "why did this review not run" question on adpeak/adpeak-mono to this: github_token was unset (direct form, App identity), GitHub's own OIDC platform check rejected the workflow file as not byte-identical to the default branch, and upstream's run.ts treats that as a soft skip -- it returns cleanly with no error, so the whole job reports green with nothing having actually happened. In that case the PR's branch had simply fallen behind a same-day rewrite of claude-review.yml on main; the PR itself never touched any workflow file.

Traced through upstream's actual run.ts: conclusion is left unset by exactly two code paths -- the workflow-validation skip, and a "no trigger found" skip that's provably unreachable through this wrapper (every mode here always sets a non-empty prompt, which is what upstream's own trigger check requires). So a winning credential attempt with no conclusion output at all can only mean the workflow-validation skip.

Resolve Claude Code result now checks for exactly that and fails the job outright with an error naming both real causes (this PR edited a workflow file, or the branch fell behind main), instead of a silent green success.

Test plan

  • Extracted the modified Resolve Claude Code result script and ran it against four scenarios with real env vars: normal success, all-credentials-genuinely-failed, normal fallback (attempt 1 fails, attempt 2 succeeds), and the new workflow-validation-skip case -- only the last one now fails, with the new error message; the other three are byte-for-byte unaffected
  • actionlint via the synthetic workflow_call wrapper: same three pre-existing findings only, nothing new
  • npm run lint / typecheck / format:check all pass

…kips a run

Upstream's own run.ts leaves its conclusion output unset on exactly one
reachable code path through this wrapper: setupGitHubToken() throwing
WorkflowValidationSkipError, when github_token is left unset (the
direct-form App-identity path) and GitHub's OIDC platform check rejects
the workflow file used for this run as not byte-identical to the current
default branch. Upstream treats this as a soft skip and returns cleanly,
so the calling step reports success with nothing having actually run --
no review, no comment, no visible signal anything is wrong. The other
code path that leaves conclusion unset ("no trigger found") is provably
unreachable through this wrapper, which always sets a non-empty prompt,
so a winning attempt with no conclusion at all can only mean the
workflow-validation skip.

Resolve Claude Code result now detects this and fails the job outright
with an error naming both possible causes (this run's own workflow file
was edited in the pull request, or the branch has fallen behind a
since-changed copy of the file on the default branch) instead of letting
the job report a misleading green success. Confirmed against a real
occurrence on adpeak/adpeak-mono, where a branch had fallen behind a
same-day rewrite of its own claude-review.yml on main.
@Mearman
Mearman marked this pull request as ready for review September 10, 2026 10:05
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review Completed 2026-09-10T10:08:52.714644Z 45f00f0 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the core claim this PR relies on directly against upstream's pinned SHA (e8c2d7c1..., v1.0.208):

  • src/entrypoints/run.ts's WorkflowValidationSkipError catch sets no conclusion output and returns cleanly (soft skip, exit 0).
  • The only other early return before conclusion is set is the "no trigger found" path in the same file, gated on checkContainsTrigger (src/github/validation/trigger.ts), whose very first check is if (prompt) return true — and this wrapper's "Compose prompt" step always emits a non-empty prompt for every mode (including generic, via its required PROMPT_FILE). So that path is genuinely unreachable through this wrapper, exactly as the PR body claims.
  • Upstream's own action.yml outputs: block (same SHA) does not expose skipped_due_to_workflow_validation_mismatch at all, confirming the wrapper has no direct signal to read and must infer the skip from an empty conclusion on a winning attempt — which is exactly what the new check does.

Traced the new action.yml block's integration with the rest of "Resolve Claude Code result": it runs after the existing "no winner" check and before the output-emission loop, so on trigger it produces steps.claude.outcome == failure with session_id left unset — every downstream step (wrap-up, fix pass, structured summary, progress-comment update) already gates on outcome/session_id correctly for that case, so nothing downstream is left in a bad state. The bash (${!WINNER_CONCLUSION_VAR:-} indirect-expansion pattern) matches existing idioms already used in the same script and is safe under set -euo pipefail.

The README/CLAUDE.md wording change (they're the same file — CLAUDE.md is a symlink to README.md) accurately describes the mechanism and gives a correct, actionable next step for both real causes (self-editing the workflow file vs. a stale branch).

No related open issue exists to link (the repository currently has zero issues, open or closed). Of the other open PRs, only #47 (dependabot bump of the pinned upstream SHA to 1.0.215) touches the same general area (the pinned action and its run.ts behaviour this PR's reasoning depends on) — worth a quick re-check of this same reasoning against 1.0.215 once that lands, but nothing to block on here since it hasn't merged yet.

Title and description are already complete and accurate (clear rationale, real-world trigger via the adpeak/adpeak-mono incident, and a concrete manual test plan), so no rewrite needed.

No Blocker or Should-fix findings. Approving.

@github-actions

Copy link
Copy Markdown

🗜️ Headroom context compression

Metric Value
Requests proxied 56
Tokens saved 79975
Aggregate savings 1.2% of all tokens sent
Average per-request compression 2.6%

@Mearman
Mearman merged commit 5dd712b into main Sep 10, 2026
14 checks passed
@Mearman
Mearman deleted the feat/loud-workflow-validation-skip branch September 10, 2026 10:14
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.10.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant